# Module 'path' -- opérations courantes sur les chemins d'accès POSIX

import posix


# Concaténation intelligente de chemins d'accès.
# Insère un '/' sauf si la première partie est vide ou se termine déjà par un
# '/'.
# Ignore complètement la première partie si la deuxième partie est un chemin
# d'accès absolu (c'est-à-dire si elle commence par un '/').
#
def cat(a, b):
	if b[:1] = '/': return b
	if a = '' or a[-1:] = '/': return a + b
	return a + '/' + b


# Sépare la tête et la queue d'un chemin d'accès. La tête peut être vide; sinon
# c'est la partie du chemin d'accès qui se termine par un '/'; la queue est la
# deuxième partie du chemin d'accès, et ne contient pas de '/'.
# La queue sera vide si le chemin d'accès se termine par '/'.
#
def split(p):
	head, tail = '', ''
	for c in p:
		tail = tail + c
		if c = '/':
			head, tail = head + tail, ''
	return head, tail


# Renvoie la queue (ou nom de base) d'un chemin d'accès.
#
def basename(p):
	return split(p)[1]


# Renvoie le plus long préfixe commun à tous les éléments de la liste
# spécifiée. 
#
def commonprefix(m):
	if not m: return ''
	prefix = m[0]
	for item in m:
		for i in range(len(prefix)):
			if prefix[:i+1] <> item[:i+1]:
				prefix = prefix[:i]
				if i = 0: return ''
				break
	return prefix


# Est-ce que le fichier/répertoire spécifié existe?
#
def exists(path):
	try:
		st = posix.stat(path)
	except posix.error:
		return 0
	return 1


# Est-ce que l'objet désigné par le chemin d'accès spécifié est un répertoire
# posix?
#
def isdir(path):
	try:
		st = posix.stat(path)
	except posix.error:
		return 0
	return st[0] / 4096 = 4 # S_IFDIR


# Est-ce que l'objet désigné par le chemin d'accès spécifié est un lien
# symbolique?
# Cette fonction renverra toujours false sous les systèmes où posix.lstat
# n'existe pas.
#
def islink(path):
	try:
		st = posix.lstat(path)
	except (posix.error, NameError):
		return 0
	return st[0] / 4096 = 10 # S_IFLNK


_mounts = []

def _getmounts():
	import commands, string
	mounts = []
	data = commands.getoutput('/etc/mount')
	lines = string.splitfields(data, '\n')
	for line in lines:
		words = string.split(line)
		if len(words) >= 3 and words[1] = 'on':
			mounts.append(words[2])
	return mounts


# Est-ce que l'objet désigné par le chemin d'accès spécifié est un point de
# montage?
# Cette fonction ne marche que pour les chemins d'accès absolus et normalisés,
# et seulement si la table de montage affichée par /etc/mount est correcte.
# Désolé.
#
def ismount(path):
	if not _mounts:
		_mounts[:] = _getmounts()
	return path in _mounts


# Traverse une arborescence de répertoires.
# Pour chaque répertoire en-dessous de top (y compris top lui-même), cette
# fonction appelle func(arg, nom-rép, noms-fichiers) où nom-rép est le nom du
# répertoire et noms-fichiers est la liste des fichiers (et sous-répertoires)
# contenus dans le répertoire.
# func peut modifier la liste des noms de fichier afin d'implémenter un filtre
# ou d'imposer un ordre de visite différent.
#
def walk(top, func, arg):
	try:
		names = posix.listdir(top)
	except posix.error:
		return
	func(arg, top, names)
	exceptions = ('.', '..')
	for name in names:
		if name not in exceptions:
			name = cat(top, name)
			if isdir(name):
				walk(name, func, arg)
